package dms.repository.impl;
/**
 * @author 李健
 */
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Hibernate;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;

import dms.model.Classes;
import dms.model.Dormitory;
import dms.model.School;
import dms.model.role.Student;
import dms.model.util.FindUtil;
import dms.model.util.PageIterator;
import dms.repository.StudentRepository;
import dms.util.HibernateUtil;

public class StudentRepositoryHibernate implements StudentRepository {

	private static Log log = LogFactory.getLog(SchoolRepositoryHibernate.class);
	
	@Override
	public Student createStudent(Student studentInfo) {
		Session session = null;
		Transaction tx = null;
		 
		session = HibernateUtil.getSessionFactory().getCurrentSession();
		tx = session.beginTransaction();
		
		session.save(studentInfo);
		return studentInfo;
	}

	@Override
	public void deleteById(Long id) {
		Session session = null;
		Transaction tx = null;
		Student s = null;
		
		session = HibernateUtil.getSessionFactory().getCurrentSession();
		tx = session.beginTransaction();
		
		s = (Student) session.load(Student.class, id);
		session.delete(s);
		
	}

	@Override
	public PageIterator<Student> findAll(int start, int count) {
		Session session = null;
		Transaction tx = null;
		PageIterator<Student> iter = null;
		List<Student> list = null;
		Long allCount = null;
		
		session = HibernateUtil.getSessionFactory().getCurrentSession();
		tx = session.beginTransaction();
		
		String countQuery = "select count(*) from Student ";
		String findQuery = "select s from Student ";
		
		allCount = FindUtil.calculateAllCount(session, countQuery, null);
		list = FindUtil.getEntitiesByPage(session, findQuery, null, start, count);
		iter = new PageIterator<Student>(list, allCount, start, count);
			
		return iter;
	}

	@Override
	public Student findById(Long id) {
		Session session = null;
		Transaction tx = null;
		Student s = null;
		
		session = HibernateUtil.getSessionFactory().getCurrentSession();
		tx = session.beginTransaction();
		
		s = (Student) session.load(Student.class, id);
		//initialize property
		Hibernate.initialize(s);
	
		return s;
	}

	public PageIterator<Student> findByDormitory(int start, int count, Dormitory dormitory) {
		Session session = null;
		Transaction tx = null;
		
		List<Student> students = null;
		Long allCount = null;
		PageIterator<Student> iter = null;
		
		String queryString = "select s from Student s where s.dormitory = ?";
		String countQuery = "select count(*) from Student s where s.dormitory = ?";

		session = HibernateUtil.getSessionFactory().getCurrentSession();
		tx = session.beginTransaction();
		
		Collection params = new ArrayList();
		params.add(dormitory);
		students = FindUtil.getEntitiesByPage(session, queryString, params, start, count);
		allCount = FindUtil.calculateAllCount(session, countQuery, params);
		iter = new PageIterator<Student>(students, allCount, start, count);
		
		return iter;
	}
	
	@Override
	public PageIterator<Student> findByQuery(int start, int count, String queryStr) {
		Session session = null;
		Transaction tx = null;
		
		List<Student> students = null;
		Long allCount = null;
		PageIterator<Student> iter = null;
				
		session = HibernateUtil.getSessionFactory().getCurrentSession();
		tx = session.beginTransaction();
		
		Query query = session.createQuery("select s from Student s where s.account.name like :query or " +
										  "s.dormitory.name like :query or s.classes.name like :query " +
										  "or s.school.name like :query or s.faculty.name like :query ")
										  .setString("query", "%" + queryStr + "%")
										  .setFirstResult(0)
										  .setMaxResults(count);
		allCount = (Long) session.createQuery("select count(*) from Student s where s.account.name like :query or " +
									   "s.dormitory.name like :query or s.classes.name like :query " +
									   "or s.school.name like :query or s.faculty.name like :query ")
									   .setParameter("query", queryStr)
									   .uniqueResult();
		
			
		students = query.list();
		iter = new PageIterator<Student>(students, allCount, start, count);		
		return iter;
	}

	@Override
	public Student updateStudent(Student studentInfo) {
		Session session = null;
		Transaction tx = null;
		Student s = null;
		 
		session = HibernateUtil.getSessionFactory().getCurrentSession();
		tx = session.beginTransaction();
		
		s = (Student) session.merge(studentInfo);
		
		return s;
	}

	@Override
	public PageIterator<Student> findByClasses(int start, int count,
			Classes classes) {
		Map keyValue = new HashMap();
		keyValue.put("classes", classes);
		return this.find(start, count, keyValue);
	}

	@Override
	public PageIterator<Student> findBySchool(int start, int count,
			School school) {
		Map keyValue = new HashMap();
		keyValue.put("school", school);
		return this.find(start, count, keyValue);
	}
	
	private PageIterator<Student> find(int start, int count, Map keyValue) {
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		PageIterator<Student> students = null;
		List<Student> list = null;
		Long allCount = null;
		
		Object[] queriesAndParams = this.makeQueryAndParams(start, count, keyValue);
		String countQuery = (String) queriesAndParams[0];
		String findQuery = (String) queriesAndParams[1];
		Collection params = (Collection) queriesAndParams[2];
		
		Transaction tx = session.beginTransaction();
		allCount = FindUtil.calculateAllCount(session, countQuery, params);
		list = FindUtil.getEntitiesByPage(session, findQuery, params, start, count);
		students = new PageIterator<Student>(list, allCount, start, count);
		
		return students;
	}
	
	private Object[] makeQueryAndParams(int start, int count, Map keyValue) {
		String countQuery = "select count(*) from Student s ";
		String findQuery = " select * from Student s ";
		StringBuffer conditionQuery = new StringBuffer(" where ");
		
		Collection params = new ArrayList();
		Set entries = keyValue.entrySet();
		Iterator iter = entries.iterator();
		while (iter.hasNext()) {
			Entry entry = (Entry) iter.next();
			conditionQuery.append(" m." + entry.getKey())
						  .append("=")
						  .append(" ? and ");
			params.add(entry.getValue());
		}
		conditionQuery.append(" 1 = 1");
		countQuery += conditionQuery.toString();
		findQuery += conditionQuery.toString();
		
		return new Object[]{countQuery, findQuery, params};
	}
}




